#!/bin/bash

# change_to_txt - 为目录中没有扩展名的文件添加.txt扩展名
# 
# 描述:
#   该脚本递归遍历指定目录及其子目录，查找没有文件扩展名的文件，
#   并为这些文件添加.txt扩展名。具有扩展名的文件将保持不变。
#
# 使用方法:
#   ./change_to_txt.sh [选项] [目录路径]
# 
# 选项:
#   -h, --help        显示帮助信息
#   -n, --dry-run     仅显示将要执行的操作，不实际执行
#   -v, --verbose     显示详细输出
#   -y, --yes         跳过确认提示，直接执行操作
# 
# 示例:
#   ./change_to_txt.sh
#       处理当前目录中的文件
#
#   ./change_to_txt.sh /home/user/documents
#       处理指定目录中的文件
#
#   ./change_to_txt.sh -n /home/user/documents
#       预览将要对指定目录执行的操作，但不实际执行
#
#   ./change_to_txt.sh -v -y /home/user/documents
#       处理指定目录中的文件，显示详细输出并跳过确认提示
#
# 文件处理规则:
#   1. 只有没有扩展名的文件会被重命名为添加.txt扩展名
#   2. 已经有扩展名的文件（如 file.txt, file.log）保持不变
#   3. 以点号开头但没有扩展名的文件（如 .bashrc）会被重命名为 .bashrc.txt
#   4. 如果目标文件名已存在，则跳过该文件以防止数据丢失
#
# 安全特性:
#   1. 默认情况下，在执行任何更改之前会提示用户确认
#   2. 提供试运行模式 (-n) 以预览将要执行的操作
#   3. 自动检测并防止文件名冲突
#   4. 递归处理时跳过符号链接目录以避免无限循环
#
# 退出状态:
#   0   成功执行
#   1   发生错误（如权限问题、无效路径等）
# 
# 颜色定义
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
NC='\033[0m' # No Color

# 显示使用说明
show_usage() {
    echo "用法: $0 [选项] [目录路径]"
    echo ""
    echo "选项:"
    echo "  -h, --help     显示此帮助信息"
    echo "  -n, --dry-run  仅显示将要执行的操作，不实际执行"
    echo "  -v, --verbose  显示详细输出"
    echo "  -y, --yes      跳过确认提示，直接执行操作"
    echo ""
    echo "示例:"
    echo "  $0              # 处理当前目录"
    echo "  $0 /path/dir    # 处理指定目录"
    echo "  $0 -n /path/dir # 预览将要执行的操作"
}

# 日志函数
log_info() {
    echo -e "${GREEN}[信息]${NC} $1"
}

log_warn() {
    echo -e "${YELLOW}[警告]${NC} $1"
}

log_error() {
    echo -e "${RED}[错误]${NC} $1"
}

# 初始化变量
DRY_RUN=false
VERBOSE=false
SKIP_CONFIRM=false
TARGET_DIR=""

# 解析命令行参数
while [[ $# -gt 0 ]]; do
    case $1 in
        -h|--help)
            show_usage
            exit 0
            ;;
        -n|--dry-run)
            DRY_RUN=true
            shift
            ;;
        -v|--verbose)
            VERBOSE=true
            shift
            ;;
        -y|--yes)
            SKIP_CONFIRM=true
            shift
            ;;
        -*)
            log_error "未知选项: $1"
            show_usage
            exit 1
            ;;
        *)
            TARGET_DIR="$1"
            shift
            ;;
    esac
done

# 如果没有指定目录，则使用当前目录
if [[ -z "$TARGET_DIR" ]]; then
    TARGET_DIR="."
fi

# 检查目录是否存在
if [[ ! -d "$TARGET_DIR" ]]; then
    log_error "目录不存在: $TARGET_DIR"
    exit 1
fi

# 检查目录是否可读
if [[ ! -r "$TARGET_DIR" ]]; then
    log_error "目录不可读: $TARGET_DIR"
    exit 1
fi

# 显示操作模式
if [[ "$DRY_RUN" == true ]]; then
    log_info "试运行模式 - 仅显示将要执行的操作"
else
    log_info "实际执行模式"
    
    # 如果不是跳过确认，询问用户确认
    if [[ "$SKIP_CONFIRM" == false ]]; then
        echo ""
        read -p "确定要继续执行吗? (y/N): " -n 1 -r
        echo
        if [[ ! $REPLY =~ ^[Yy]$ ]]; then
            log_info "操作已取消"
            exit 0
        fi
    fi
fi

log_info "处理目录: $(realpath "$TARGET_DIR")"

# 初始化计数器
files_processed=0
files_renamed=0
files_skipped=0
errors=0

# 检查文件是否具有扩展名的函数
has_extension() {
    local filename="$1"
    
    # 如果文件名中没有点号，则没有扩展名
    if [[ "$filename" != *.* ]]; then
        return 1  # 没有扩展名
    fi
    
    # 特殊情况：以点号开头的文件（如 .bashrc）
    if [[ "$filename" == .* ]]; then
        # 如果只有前导点号（如 .bashrc），则没有扩展名
        if [[ "${filename#.*}" != *.* ]]; then
            return 1  # 没有扩展名
        fi
    fi
    
    # 其他情况，文件有扩展名
    return 0  # 有扩展名
}

# 递归遍历目录的函数
process_directory() {
    local dir="$1"
    
    # 遍历目录中的所有项目
    for item in "$dir"/* "$dir"/.*; do
        # 跳过当前目录和父目录的特殊条目
        [[ "$(basename "$item")" == "." || "$(basename "$item")" == ".." ]] && continue
        
        # 检查项目是否存在（处理无匹配项的情况）
        [[ ! -e "$item" ]] && continue
        
        if [[ -d "$item" ]]; then
            # 如果是目录，递归处理（跳过符号链接目录避免无限循环）
            if [[ ! -L "$item" ]]; then
                process_directory "$item"
            fi
        elif [[ -f "$item" ]]; then
            # 如果是文件，检查是否有扩展名
            filename=$(basename "$item")
                
            # 检查文件是否已经有扩展名
            if ! has_extension "$filename"; then
                # 文件没有扩展名，需要重命名
                dirname=$(dirname "$item")
                new_name="${filename}.txt"
                new_path="$dirname/$new_name"
                
                # 检查目标文件是否已存在
                if [[ -e "$new_path" ]]; then
                    log_warn "目标文件已存在，跳过: $item -> $new_name"
                    ((files_skipped++))
                    continue
                fi
                
                # 执行重命名操作或仅显示
                if [[ "$DRY_RUN" == true ]]; then
                    echo "将重命名: $item -> $new_name"
                else
                    if mv "$item" "$new_path"; then
                        if [[ "$VERBOSE" == true ]]; then
                            echo "已重命名: $item -> $new_name"
                        fi
                        ((files_renamed++))
                    else
                        log_error "重命名失败: $item"
                        ((errors++))
                    fi
                fi
                ((files_processed++))
            else
                # 文件已有扩展名，跳过
                ((files_skipped++))
                [[ "$VERBOSE" == true ]] && echo "已跳过（已有扩展名）: $item"
            fi
        fi
    done
}

# 开始处理
log_info "开始处理文件..."
process_directory "$TARGET_DIR"

# 显示结果统计
echo ""
log_info "处理完成"
echo "处理的文件数: $files_processed"
echo "重命名的文件数: $files_renamed"
echo "跳过的文件数: $files_skipped"
echo "错误数: $errors"

if [[ "$DRY_RUN" == true ]]; then
    log_info "以上为试运行结果，未实际执行文件重命名操作"
fi

# 如果有错误，退出码为1
if [[ $errors -gt 0 ]]; then
    exit 1
fi

exit 0